#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/usb.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/hid.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <video/display_timing.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/fb.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
#include <linux/list.h>

struct vir_i2c_dev_inf {
    unsigned int addr;
    unsigned char eeprom_buffer[512];
    unsigned int index;
    int (*write)(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, unsigned int *addr);
    int (*read)(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, unsigned int *addr);
};

struct vir_i2c_dev_list {
    struct vir_i2c_dev_inf *dev;
    struct list_head list;
};

struct vir_i2c_algo_st {
	struct i2c_adapter	adapter;
    unsigned int		bitrate;
    struct vir_i2c_dev_list vir_dev_list;
    struct platform_device *pdev;
};

static int vir_eeproom_write(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, unsigned int *addr)
{
    struct vir_i2c_dev_inf *dev_ops = container_of(addr, struct vir_i2c_dev_inf, addr);
    unsigned int i = 0;

    // eeproom写数据,第一个为要写的寄存器位置
    if (msg->len >= 1) {
        if (msg->buf[0] < 512) {
            dev_ops->index = msg->buf[0];
            for (i = 0; i < msg->len; i++) {
                dev_ops->eeprom_buffer[dev_ops->index++] = msg->buf[i];
                if (dev_ops->index == 512) {
                    dev_ops->index = 0;
                }
            }
        }
    }

    return 0;
}

static int vir_eeproom_read(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, unsigned int *addr)
{
    struct vir_i2c_dev_inf *dev_ops = container_of(addr, struct vir_i2c_dev_inf, addr);
    unsigned int i = 0;

    for (i = 0; i < msg->len; i++) {
        msg->buf[i] = dev_ops->eeprom_buffer[dev_ops->index++];
        if (dev_ops->index == 512) {
            dev_ops->index = 0;
        }
    }

    return 0;
}

static struct vir_i2c_dev_inf eeproom = {
    .addr  = 0x50,
    .write = vir_eeproom_write,
    .read  = vir_eeproom_read,
    .index = 0,
};

static struct vir_i2c_dev_inf eeproom1 = {
    .addr  = 0x31,
    .write = vir_eeproom_write,
    .read  = vir_eeproom_read,
    .index = 0,
};


#define VIR_DEV_DRIVER_N 32

static struct vir_i2c_dev_inf *vir_dev_driver[VIR_DEV_DRIVER_N] = {
    &eeproom,
    &eeproom1,
};

static int regist_vir_i2c_dev(unsigned int addr, struct vir_i2c_algo_st *vir_i2c)
{
    struct vir_i2c_dev_list *tmp = NULL;
    int ret = 0;
    unsigned int i = 0;
    
    tmp = devm_kzalloc(&vir_i2c->pdev->dev, sizeof(struct vir_i2c_dev_list), GFP_KERNEL);
    if (IS_ERR(tmp)) {
        ret = PTR_ERR(tmp);
        dev_err(&vir_i2c->pdev->dev, "Failed to allocate struct vir_i2c_dev_list: %d\n", ret);
        return ret;
	}

    for (i = 0; i < VIR_DEV_DRIVER_N; i++) {
        if (vir_dev_driver[i]->addr == addr) {
            dev_err(NULL, "vir_dev_driver[%d]->addr=0x%x, addr=0x%x\n", i, vir_dev_driver[i]->addr, addr);
            tmp->dev = vir_dev_driver[i];
            list_add_tail(&tmp->list, &vir_i2c->vir_dev_list.list);
            break;
        }
    }
    
    if (i == 32) {
        dev_err(NULL, "can't find vir dev info \n");
        return 0;
    }

    return 0;
}

static int parse_vir_i2c_dt(struct device_node *np, struct vir_i2c_algo_st *vir_i2c)
{
    /* 一次获取子节点 */
    struct device_node *node = NULL;
    struct device_node *prev = NULL;
    unsigned int addr = 0;
    int ret = 0;
    const char *name;

    // 跳过status是"disabled"的子节点
    // prev = NULL，表示从第一个子节点开始搜索
    while ((node = of_get_next_available_child(np, prev)) != NULL) {
        // 更新prev节点
        prev = node;
    
        // 获取设备的名字
        of_property_read_string(node, "compatible", &name);
        dev_err(NULL, "vir dev name %s\n", name);
        
        // 获取设备树中的vir reg
        ret = of_property_read_u32(node, "reg", &addr);
        if (ret < 0) {
            dev_err(NULL, "get reg failed\n");
            return -EINVAL;
        }

        dev_err(NULL, "vir dev addr 0x%x\n", addr);
        
        // 获取子节点的信息
        ret = regist_vir_i2c_dev(addr, vir_i2c);
        if (ret < 0) {
            dev_err(NULL, "regist_vir_i2c_dev failed\n");
            return -EINVAL;
        }
    }

    return 0;
}

static int vir_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
    // 实现了一般的I2C传输，用来传输一个或多个i2c_msg
    int i = 0;
    struct vir_i2c_algo_st *vir_i2c = i2c_get_adapdata(adapter);
    struct list_head *ppos = NULL;    // 当前处理的i2c_msg的ADDR的设备信息和操作
    struct vir_i2c_dev_list *tmp = NULL;
    struct vir_i2c_dev_inf *dev_ops = NULL;

    // 判断链表是否为空
    if (list_empty(&vir_i2c->vir_dev_list.list)) {
        return -EINVAL;
    }
    
    // 模仿虚拟的设备,根据虚拟的addr地址,去链表中寻找地址比较支持,调用提供对应的读函数和写函数
    // 判断发送的msgs的设备的虚拟inf信息
    /* 遍历链表 */
    list_for_each(ppos, &vir_i2c->vir_dev_list.list) {
        tmp = list_entry(ppos, struct vir_i2c_dev_list, list);
        // 获取虚拟的ADDR设备
        if (tmp->dev->addr == msgs[i].addr) {
            dev_ops = tmp->dev;
            break;
        } 
    }

    // 不存在该ADDR的操作函数返回
    if (dev_ops == NULL) {
        return -EINVAL;
    }
    
    for (i = 0; i < num; i++) {
        // 判断msgs的类型
        if (msgs[i].flags & I2C_M_RD) {
            if (dev_ops)
                dev_ops->read(adapter, &msgs[i], &dev_ops->addr);
        } else {
            if (dev_ops)
                dev_ops->write(adapter, &msgs[i], &dev_ops->addr);
        }
    }

    return i;
}

static u32 vir_i2c_func(struct i2c_adapter *adapter)
{
    return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
	       I2C_FUNC_PROTOCOL_MANGLING;
}

static const struct i2c_algorithm vir_i2c_algo = {
	.master_xfer	= vir_i2c_xfer,
	.functionality	= vir_i2c_func,
};

static int vir_i2c_algo_dev_probe(struct platform_device *pdev)
{
    struct vir_i2c_algo_st *vir_i2c;
    struct device_node *np = NULL;
    struct device *dev = &pdev->dev;
    int ret = 0;

    np = dev->of_node;
    if (!np) {
        dev_err(dev, "could not find device info\n");
        return -EINVAL;
    }

    vir_i2c = devm_kzalloc(&pdev->dev, sizeof(struct vir_i2c_algo_st), GFP_KERNEL);
    if (!vir_i2c) {
        return -ENOMEM;
    }

    /* 为真实的i2c controler写驱动需要以下步骤参考i2c-imx,使用中断的方式收发数据 */
    /* 获取中断 */
    /* 获取资源 */
    /* 获取时钟 */

    /* 设置i2c_apdater */
    strlcpy(vir_i2c->adapter.name, pdev->name, sizeof(vir_i2c->adapter.name));
    vir_i2c->adapter.owner = THIS_MODULE;
    vir_i2c->adapter.algo = &vir_i2c_algo;
    vir_i2c->adapter.dev.parent = &pdev->dev;
    vir_i2c->adapter.nr = pdev->id;
    vir_i2c->adapter.dev.of_node = pdev->dev.of_node;

    vir_i2c->pdev = pdev;


    /* Set up adapter data */
	i2c_set_adapdata(&vir_i2c->adapter, vir_i2c);

	/* Set up platform driver data */
	platform_set_drvdata(pdev, vir_i2c);

    /* Set up clock divider */
    /* 获取设备树中的I2C的设置频率 */
    ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &vir_i2c->bitrate);
    if (ret < 0) {
        dev_err(dev, "get clock-frequency failed\n");
        vir_i2c->bitrate = 100000;
    }

    /* 通过设备树获取需要模拟的子节点 */

    /* 初始化链表 */
    INIT_LIST_HEAD(&vir_i2c->vir_dev_list.list);
    
    /* 根据子节点个数存入对应的数据 */
    parse_vir_i2c_dt(np, vir_i2c);

    // i2c_add_adapter(adap); // 不管adap->nr原来是什么，都动态设置adap->nr
    // ret = i2c_add_numbered_adapter(adap); // 如果adap->nr == -1 则动态分配nr; 否则使用该nr
    
    /* Add I2C adapter */
	ret = i2c_add_numbered_adapter(&vir_i2c->adapter);
	if (ret < 0)
		return -ret;
    
    return 0;
}

static int vir_i2c_algo_dev_remove(struct platform_device *pdev)
{
    struct vir_i2c_algo_st *vir_i2c = platform_get_drvdata(pdev);

    /* remove adapter */
    i2c_del_adapter(&vir_i2c->adapter);

    return 0;
}

static const struct of_device_id vir_i2c_algo_dev[] = {
    { .compatible = "jz2440,virtual_i2c_algo_dev", },
    {},
};
MODULE_DEVICE_TABLE(of, vir_i2c_algo_dev);


static struct platform_driver vir_i2c_algo_master_driver = {
    .probe = vir_i2c_algo_dev_probe,
    .remove = vir_i2c_algo_dev_remove,
    .driver = {
        .name = "jz2440-vir-i2c-algo-master-dev",
        .of_match_table = of_match_ptr(vir_i2c_algo_dev),
    }
};


/*
 * init入口函数
*/
static int vir_i2c_algo_master_init(void)
{
    int ret = platform_driver_register(&vir_i2c_algo_master_driver);
    if (ret < 0) {
        dev_err(NULL, "vir_i2c_algo_master_init failed\n");
        return -EBUSY;
    }
    
    return ret;
}

/*
 * exit出口函数
 */
static void vir_i2c_algo_master_exit(void)
{
    platform_driver_unregister(&vir_i2c_algo_master_driver);
    return;
}

module_init(vir_i2c_algo_master_init);
module_exit(vir_i2c_algo_master_exit);


MODULE_AUTHOR("huang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("virtual i2c algo driver");



